package com.zff.rental.service.oss;

import com.tencent.cloud.CosStsClient;
import com.tencent.cloud.Policy;
import com.tencent.cloud.Response;
import com.tencent.cloud.Statement;
import com.tencent.cloud.cos.util.Jackson;
import com.zff.rental.vo.cos.TencentCosParams;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.TreeMap;

/**
 * @author HCY
 */
@Service
@Slf4j
public class TencentCosService {
    /**
     * 云 api appId
     */
    private static final String APP_ID = "1252028025";
    /**
     * 云 api 密钥 SecretId
     */
    private static final String SECRET_ID = "AKIDMcjpkZYQBk5EAsNehXBgy3wy1vpeJo7D";

    /**
     * api 密钥 SecretKey
     */
    private static final String SECRET_KEY = "we9QTJxPdeS2PYTAdsupW0Gk391g8NPE";

    /**
     * bucket
     */
    private static final String BUCKET = "hebizhi-1252028025";

    /**
     * region
     */
    private static final String REGION = "ap-guangzhou";

    /**
     * 临时密钥有效时长，单位是秒，默认 1800 秒，目前主账号最长 2 小时（即 7200 秒），子账号最长 36 小时（即 129600）秒
     */
    private static final Integer DURATION_SECONDS = 1800;

    /**
     * 获取临时密钥
     */
    public Response getCredential(TencentCosParams params) {
        String bucket = params.getBucket();
        if (bucket == null || bucket.isEmpty()) {
            bucket = BUCKET;
        }
        String region = params.getRegion();
        if (region == null || region.isEmpty()) {
            region = REGION;
        }

        TreeMap<String, Object> config = new TreeMap<>();
        config.put("secretId", SECRET_ID);
        config.put("secretKey", SECRET_KEY);

        Policy policy = new Policy();
        config.put("durationSeconds", DURATION_SECONDS);
        config.put("bucket", bucket);
        config.put("region", region);

        // 开始构建一条 statement
        Statement statement = new Statement();
        statement.setEffect("allow");
        /**
         * 密钥的权限列表。必须在这里指定本次临时密钥所需要的权限。
         * 权限列表请参见 https://cloud.tencent.com/document/product/436/31923
         * 规则为 {project}:{interfaceName}
         * project : 产品缩写  cos相关授权为值为cos,数据万象(数据处理)相关授权值为ci
         * 授权所有接口用*表示，例如 cos:*,ci:*
         * 添加一批操作权限 :
         */
        statement.addActions(new String[]{
                //简单上传操作
                "cos:PutObject",
                // 表单上传、小程序上传
                "cos:PostObject",
                // 分块上传
                "cos:InitiateMultipartUpload",
                "cos:ListMultipartUploads",
                "cos:ListParts",
                "cos:UploadPart",
                "cos:CompleteMultipartUpload",
                // 处理相关接口一般为数据万象产品 权限中以ci开头
                // 创建媒体处理任务
                "ci:CreateMediaJobs",
                // 文件压缩
                "ci:CreateFileProcessJobs"
        });

        /**
         * 这里改成允许的路径前缀，可以根据自己网站的用户登录态判断允许上传的具体路径
         * 资源表达式规则分对象存储(cos)和数据万象(ci)两种
         * 数据处理、审核相关接口需要授予ci资源权限
         *  cos : qcs::cos:{region}:uid/{appid}:{bucket}/{path}
         *  ci  : qcs::ci:{region}:uid/{appid}:bucket/{bucket}/{path}
         * 列举几种典型的{path}授权场景：
         * 1、允许访问所有对象："*"
         * 2、允许访问指定的对象："a/a1.txt", "b/b1.txt"
         * 3、允许访问指定前缀的对象："a*", "a/*", "b/*"
         *  如果填写了“*”，将允许用户访问所有资源；除非业务需要，否则请按照最小权限原则授予用户相应的访问权限范围。
         *
         * 示例：授权hebizhi-1252028025 bucket目录下的所有资源给cos和ci 授权两条Resource
         */
//        statement.addResources(new String[]{
//                "qcs::cos:ap-guangzhou:uid/1252028025:hebizhi-1252028025/*",
//                "qcs::ci:ap-guangzhou:uid/1252028025:bucket/hebizhi-1252028025/*"});
        statement.addResources(new String[]{
                "qcs::cos:" + region + ":uid/" + APP_ID + ":" + bucket + "/*",
                "qcs::ci:" + region + ":uid/" + APP_ID + ":bucket/" + bucket + "/*"});

        // 把一条 statement 添加到 policy
        // 可以添加多条
        policy.addStatement(statement);
        // 将 Policy 示例转化成 String，可以使用任何 json 转化方式，这里是本 SDK 自带的推荐方式
        config.put("policy", Jackson.toJsonPrettyString(policy));

        try {
            return CosStsClient.getCredential(config);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}